# coding:utf-8
'''
Created on 2009-12-30

@author: Jason Green
@author-email: guileen@gmail.com
'''
from django.conf import settings
from django.http import HttpRequest
from django.template.context import RequestContext
from django.template.loader import \
    render_to_string as _original_render_to_string
from djangosnippets.utils.importlib import import_any
from jinja2 import Environment
from jinja2.sandbox import SandboxedEnvironment, ImmutableSandboxedEnvironment
import django.template.loader as djloader

def _new_env(env_class):
    from jinja2 import PackageLoader, ChoiceLoader, FileSystemLoader
    loader_array = []
    for pth in getattr(settings, 'TEMPLATE_DIRS', ()):
        loader_array.append(FileSystemLoader(pth))

    for app in settings.INSTALLED_APPS:
        if not app.startswith('django.'):
            try:
                loader_array.append(PackageLoader(app))
            except:
                pass
    loader_array.append(PackageLoader('djangosnippets'))

    # Setup environment
    global_exts = getattr(settings, 'JINJA_EXTS', ())
    env = object.__new__(env_class)
    env_class.__init__(env, extensions=global_exts, loader=ChoiceLoader(loader_array))
    return env

def _init_env(env):
    from django.core.urlresolvers import get_callable
    from django.utils import translation
    from djangosnippets.utils.translation import ugettext_language
    global_exts = getattr(settings, 'JINJA_EXTS', ())
    if 'jinja2.ext.i18n' in global_exts:
        env.install_gettext_translations(translation)
        env.globals['ugettext_language'] = ugettext_language
    # Add user Globals, Filters, Tests
    global_imports = getattr(settings, 'JINJA_GLOBALS', ())
    global_imports += ('djangosnippets.contrib.generic.modelhelper',)
    for imp in global_imports:
#        try:
#            method = get_callable(imp)
#            method_name = getattr(method, 'jinja_name', None) or method.__name__
#        except:
        method = import_any(imp)
        method_name = getattr(method, 'jinja_name', None) or imp[imp.rfind('.') + 1:]
        env.globals[method_name] = method

    env.globals['settings'] = settings
    env.globals['get_language'] = translation.get_language
    env.globals['get_language_bidi'] = translation.get_language_bidi

    import datetime
    env.globals['datetime'] = datetime

    global_filters = getattr(settings, 'JINJA_FILTERS', ())
    for imp in global_filters:
        method = get_callable(imp)
        method_name = getattr(method, 'jinja_name', None)
        if not method_name == None:
            env.filters[method_name] = method
        else:
            env.filters[method.__name__] = method

    global_tests = getattr(settings, 'JINJA_TESTS', ())
    for imp in global_tests:
        method = get_callable(imp)
        method_name = getattr(method, 'jinja_name', None)
        if not method_name == None:
            env.tests[method_name] = method
        else:
            env.tests[method.__name__] = method

def install(env=Environment):
    if(isinstance(env, type) and (env == Environment or issubclass(env, Environment))):
        env = _new_env(env)
    _init_env(env)

    #override jinja2.Template.render
    from jinja2 import Template
    from django.template.context import Context
    _raw_render = Template.render
    def _new_render(self, *args, **kwargs):
        if(len(args) > 0 and isinstance(args[0], Context)):
            c = {}
            for d in args[0].dicts:
                c.update(d)
            return _raw_render(self, c)
        return _raw_render(self, *args, **kwargs)
    Template.render = _new_render

    #override djloader.get_template
    from django.template.loader import get_template as _original_get_template
    from jinja2.exceptions import TemplateNotFound
    from django.template import TemplateDoesNotExist
    def get_template(template_name):
        for skip_path in getattr(settings, 'KEEP_DJANGO_TEMPLATES', ()):
            if template_name.startswith(skip_path):
                return _original_get_template(template_name)
#        try:
        return env.get_template(template_name)
#        except TemplateNotFound:
#            raise TemplateDoesNotExist

    def select_template(template_name_list):
        "Given a list of template names, returns the first that can be loaded."
        for template_name in template_name_list:
            try:
                return get_template(template_name)
            except TemplateDoesNotExist:
                continue
            except TemplateNotFound:
                continue
        # If we get here, none of the templates could be loaded
        raise TemplateNotFound, ', '.join(template_name_list)

    djloader.get_template = get_template
    djloader.select_template = select_template

    from django.views.debug import ExceptionReporter
    from django.utils.html import escape
    from jinja2 import TemplateError
    _origin_get_template_exception_info = ExceptionReporter.get_template_exception_info
    def _get_template_exception_info(self):
        if(not isinstance(self.exc_value, TemplateError)):
            return _origin_get_template_exception_info(self)
#        origin, (start, end) = self.exc_value.source
        f = open(self.exc_value.filename, 'r')
        source_lines = f.readlines()
        f.close()
        line = self.exc_value.lineno
        during = escape(source_lines[line - 1])
        source_lines = [(num + 1, escape(v)) for num, v in enumerate(source_lines)]
        context_lines = 10
#        before = during = after = ""
        total = len(source_lines)
        top = max(1, line - context_lines)
        bottom = min(total, line + 1 + context_lines)

        self.template_info = {
            'message': self.exc_value.args[0],
            'source_lines': source_lines[top - 1:bottom - 1],
            'before': "",
            'during': during,
            'after': "",
            'top': top,
            'bottom': bottom,
            'total': total,
            'line': line,
            'name': self.exc_value.name,
        }
    ExceptionReporter.get_template_exception_info = _get_template_exception_info


def _render_to_string(template_name, dictionary=None, context_instance=None):
    if context_instance == None:
        request = dictionary.get('request', None)
        if request:
            context_instance = RequestContext(request)
    elif isinstance(context_instance, HttpRequest):
        context_instance = RequestContext(context_instance)
    return _original_render_to_string(template_name, dictionary, context_instance)
djloader.render_to_string = _render_to_string

def install_sandbox():
    install(SandboxedEnvironment)

def install_immutable():
    install(ImmutableSandboxedEnvironment)
